#ifndef xpack_test_utils_value_holder
#define xpack_test_utils_value_holder
#pragma push_macro("xuser")
#undef  xuser
#define xuser mixc::test_utils_value_holder::inc
#include"test/helper.hpp" // 需要放第一
#include"define/nullref.hpp"
#include"utils/memory.hpp"
#include"utils/value_holder.hpp"
#pragma pop_macro("xuser")

namespace mixc::test_utils_value_holder{
    using nlrd = inc::helper::nlrd_counter;

    xtest("value_holder") {
        nlrd::reset_counter();

        // 测试不设置成员
        {
            inc::value_holder<nlrd> x;
            xassert_eq(x->value, inc::nullref);
            xassert_eq(x->is_hold_value, false);
            xassert_nlrd(0, 0, 0, 0);
        }

        xassert_nlrd(0, 0, 0, 0);



        // 测试拷贝构造函数
        {
            inc::value_holder<nlrd> x(nlrd{});
            xassert_eq(x->is_hold_value, true);
            xassert_nlrd(1, 0, 1, 1);
        }

        xassert_nlrd(0, 0, 0, 1);



        // 测试赋值函数
        {
            inc::value_holder<nlrd> x;
            x.hold(nlrd{});
            xassert_ne(x->value, inc::nullref);
            xassert_eq(x->is_hold_value, true);
            xassert_nlrd(1, 0, 1, 1);
        }

        xassert_nlrd(0, 0, 0, 1);



        // 测试 discard 接口
        {
            inc::value_holder<nlrd> x;
            x.discard();
            xassert_eq(x->is_hold_value, false);
            xassert_nlrd(0, 0, 0, 0);

            x.hold(nlrd{});
            xassert_ne(x->value, inc::nullref);
            xassert_eq(x->is_hold_value, true);
            xassert_nlrd(1, 0, 1, 1);

            x.discard();
            xassert_eq(x->is_hold_value, false);
            xassert_nlrd(0, 0, 0, 1);
        }

        xassert_nlrd(0, 0, 0, 0);



        // 测试 hand_over
        {
            inc::value_holder<nlrd> x0;
            inc::value_holder<nlrd> x1;
            x0 = x1.hand_over();
            xassert_eq(x0->value, inc::nullref);
            xassert_eq(x1->value, inc::nullref);
            xassert_eq(x0->is_hold_value, false);
            xassert_eq(x1->is_hold_value, false);
            xassert_nlrd(0, 0, 0, 0);
        }
        xassert_nlrd(0, 0, 0, 0);

        {
            inc::value_holder<nlrd> x0(nlrd{});
            inc::value_holder<nlrd> x1;
            xassert_nlrd(1, 0, 1, 1);
            xassert(x0->value != inc::nullref);
            xassert(x1->value == inc::nullref);
            xassert_eq(x0->is_hold_value, true);
            xassert_eq(x1->is_hold_value, false);
            x0 = x1.hand_over();
            xassert(x0->value == inc::nullref);
            xassert(x1->value == inc::nullref);
            xassert_eq(x0->is_hold_value, false);
            xassert_eq(x1->is_hold_value, false);
            xassert_nlrd(0, 0, 0, 1);
        }
        
        xassert_nlrd(0, 0, 0, 0);

        {
            inc::value_holder<nlrd> x0;
            inc::value_holder<nlrd> x1(nlrd{});;
            xassert_nlrd(1, 0, 1, 1);
            x0 = x1.hand_over();
            xassert_eq(x0->is_hold_value, true);
            xassert_eq(x1->is_hold_value, false);
            xassert_nlrd(0, 0, 0, 0);
        }
        
        xassert_nlrd(0, 0, 0, 1);

        {
            inc::value_holder<nlrd> x0(nlrd{});;
            inc::value_holder<nlrd> x1(nlrd{});;
            xassert_nlrd(2, 0, 2, 2);
            x0 = x1.hand_over();
            xassert_eq(x0->is_hold_value, true);
            xassert_eq(x1->is_hold_value, false);
            xassert_nlrd(0, 0, 0, 1);
        }

        xassert_nlrd(0, 0, 0, 1);

        {
            inc::value_holder<nlrd> x0(nlrd{});;
            inc::value_holder<nlrd> x1;
            xassert_nlrd(1, 0, 1, 1);
            x0.discard();
            xassert_eq(x0->is_hold_value, false);
            xassert_nlrd(0, 0, 0, 1);

            x1 = x0.hand_over();
            xassert_eq(x1->is_hold_value, false);
            xassert_nlrd(0, 0, 0, 0);
        }
        
        xassert_nlrd(0, 0, 0, 0);



        {
            nlrd foo{};
            xassert_nlrd(1, 0, 0, 0);
            inc::value_holder<nlrd> x0(foo);
            xassert_nlrd(0, 1, 0, 0);
        }

        xassert_nlrd(0, 0, 0, 2);



        {
            nlrd foo{};
            xassert_nlrd(1, 0, 0, 0);
            inc::value_holder<nlrd> x0;
            x0.hold(foo);
            xassert_nlrd(0, 1, 0, 0);
        }

        xassert_nlrd(0, 0, 0, 2);
    };
}

#endif
